home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Modules / cgen.py < prev    next >
Text File  |  1995-12-21  |  13KB  |  533 lines

  1. ########################################################################
  2. # Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
  3. # The Netherlands.
  4. #
  5. #                         All Rights Reserved
  6. #
  7. # Permission to use, copy, modify, and distribute this software and its
  8. # documentation for any purpose and without fee is hereby granted,
  9. # provided that the above copyright notice appear in all copies and that
  10. # both that copyright notice and this permission notice appear in
  11. # supporting documentation, and that the names of Stichting Mathematisch
  12. # Centrum or CWI not be used in advertising or publicity pertaining to
  13. # distribution of the software without specific, written prior permission.
  14. #
  15. # STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. # FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. # FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. ########################################################################
  23.  
  24. # Python script to parse cstubs file for gl and generate C stubs.
  25. # usage: python cgen.py <cstubs >glmodule.c
  26. #
  27. # NOTE: You  must first make a python binary without the "GL" option
  28. #    before you can run this, when building Python for the first time.
  29. #    See comments in the Makefile.
  30. #
  31. # XXX BUG return arrays generate wrong code
  32. # XXX need to change error returns into gotos to free mallocked arrays
  33.  
  34.  
  35. import string
  36. import sys
  37.  
  38.  
  39. # Function to print to stderr
  40. #
  41. def err(*args):
  42.     savestdout = sys.stdout
  43.     try:
  44.         sys.stdout = sys.stderr
  45.         for i in args:
  46.             print i,
  47.         print
  48.     finally:
  49.         sys.stdout = savestdout
  50.  
  51.  
  52. # The set of digits that form a number
  53. #
  54. digits = '0123456789'
  55.  
  56.  
  57. # Function to extract a string of digits from the front of the string.
  58. # Returns the leading string of digits and the remaining string.
  59. # If no number is found, returns '' and the original string.
  60. #
  61. def getnum(s):
  62.     n = ''
  63.     while s and s[0] in digits:
  64.         n = n + s[0]
  65.         s = s[1:]
  66.     return n, s
  67.  
  68.  
  69. # Function to check if a string is a number
  70. #
  71. def isnum(s):
  72.     if not s: return 0
  73.     for c in s:
  74.         if not c in digits: return 0
  75.     return 1
  76.  
  77.  
  78. # Allowed function return types
  79. #
  80. return_types = ['void', 'short', 'long']
  81.  
  82.  
  83. # Allowed function argument types
  84. #
  85. arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
  86.  
  87.  
  88. # Need to classify arguments as follows
  89. #    simple input variable
  90. #    simple output variable
  91. #    input array
  92. #    output array
  93. #    input giving size of some array
  94. #
  95. # Array dimensions can be specified as follows
  96. #    constant
  97. #    argN
  98. #    constant * argN
  99. #    retval
  100. #    constant * retval
  101. #
  102. # The dimensions given as constants * something are really
  103. # arrays of points where points are 2- 3- or 4-tuples
  104. #
  105. # We have to consider three lists:
  106. #    python input arguments
  107. #    C stub arguments (in & out)
  108. #    python output arguments (really return values)
  109. #
  110. # There is a mapping from python input arguments to the input arguments
  111. # of the C stub, and a further mapping from C stub arguments to the
  112. # python return values
  113.  
  114.  
  115. # Exception raised by checkarg() and generate()
  116. #
  117. arg_error = 'bad arg'
  118.  
  119.  
  120. # Function to check one argument.
  121. # Arguments: the type and the arg "name" (really mode plus subscript).
  122. # Raises arg_error if something's wrong.
  123. # Return type, mode, factor, rest of subscript; factor and rest may be empty.
  124. #
  125. def checkarg(type, arg):
  126.     #
  127.     # Turn "char *x" into "string x".
  128.     #
  129.     if type == 'char' and arg[0] == '*':
  130.         type = 'string'
  131.         arg = arg[1:]
  132.     #
  133.     # Check that the type is supported.
  134.     #
  135.     if type not in arg_types:
  136.         raise arg_error, ('bad type', type)
  137.     if type[:2] == 'u_':
  138.         type = 'unsigned ' + type[2:]
  139.     #
  140.     # Split it in the mode (first character) and the rest.
  141.     #
  142.     mode, rest = arg[:1], arg[1:]
  143.     #
  144.     # The mode must be 's' for send (= input) or 'r' for return argument.
  145.     #
  146.     if mode not in ('r', 's'):
  147.         raise arg_error, ('bad arg mode', mode)
  148.     #
  149.     # Is it a simple argument: if so, we are done.
  150.     #
  151.     if not rest:
  152.         return type, mode, '', ''
  153.     #    
  154.     # Not a simple argument; must be an array.
  155.     # The 'rest' must be a subscript enclosed in [ and ].
  156.     # The subscript must be one of the following forms,
  157.     # otherwise we don't handle it (where N is a number):
  158.     #    N
  159.     #    argN
  160.     #    retval
  161.     #    N*argN
  162.     #    N*retval
  163.     #
  164.     if rest[:1] <> '[' or rest[-1:] <> ']':
  165.         raise arg_error, ('subscript expected', rest)
  166.     sub = rest[1:-1]
  167.     #
  168.     # Is there a leading number?
  169.     #
  170.     num, sub = getnum(sub)
  171.     if num:
  172.         # There is a leading number
  173.         if not sub:
  174.             # The subscript is just a number
  175.             return type, mode, num, ''
  176.         if sub[:1] == '*':
  177.             # There is a factor prefix
  178.             sub = sub[1:]
  179.         else:
  180.             raise arg_error, ('\'*\' expected', sub)
  181.     if sub == 'retval':
  182.         # size is retval -- must be a reply argument
  183.         if mode <> 'r':
  184.             raise arg_error, ('non-r mode with [retval]', mode)
  185.     elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
  186.         raise arg_error, ('bad subscript', sub)
  187.     #
  188.     return type, mode, num, sub
  189.  
  190.  
  191. # List of functions for which we have generated stubs
  192. #
  193. functions = []
  194.  
  195.  
  196. # Generate the stub for the given function, using the database of argument
  197. # information build by successive calls to checkarg()
  198. #
  199. def generate(type, func, database):
  200.     #
  201.     # Check that we can handle this case:
  202.     # no variable size reply arrays yet
  203.     #
  204.     n_in_args = 0
  205.     n_out_args = 0
  206.     #
  207.     for a_type, a_mode, a_factor, a_sub in database:
  208.         if a_mode == 's':
  209.             n_in_args = n_in_args + 1
  210.         elif a_mode == 'r':
  211.             n_out_args = n_out_args + 1
  212.         else:
  213.             # Can't happen
  214.             raise arg_error, ('bad a_mode', a_mode)
  215.         if (a_mode == 'r' and a_sub) or a_sub == 'retval':
  216.             err('Function', func, 'too complicated:',
  217.                 a_type, a_mode, a_factor, a_sub)
  218.             print '/* XXX Too complicated to generate code for */'
  219.             return
  220.     #
  221.     functions.append(func)
  222.     #
  223.     # Stub header
  224.     #
  225.     print
  226.     print 'static object *'
  227.     print 'gl_' + func + '(self, args)'
  228.     print '\tobject *self;'
  229.     print '\tobject *args;'
  230.     print '{'
  231.     #
  232.     # Declare return value if any
  233.     #
  234.     if type <> 'void':
  235.         print '\t' + type, 'retval;'
  236.     #
  237.     # Declare arguments
  238.     #
  239.     for i in range(len(database)):
  240.         a_type, a_mode, a_factor, a_sub = database[i]
  241.         print '\t' + a_type,
  242.         brac = ket = ''
  243.         if a_sub and not isnum(a_sub):
  244.             if a_factor:
  245.                 brac = '('
  246.                 ket = ')'
  247.             print brac + '*',
  248.         print 'arg' + `i+1` + ket,
  249.         if a_sub and isnum(a_sub):
  250.             print '[', a_sub, ']',
  251.         if a_factor:
  252.             print '[', a_factor, ']',
  253.         print ';'
  254.     #
  255.     # Find input arguments derived from array sizes
  256.     #
  257.     for i in range(len(database)):
  258.         a_type, a_mode, a_factor, a_sub = database[i]
  259.         if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
  260.             # Sending a variable-length array
  261.             n = eval(a_sub[3:])
  262.             if 1 <= n <= len(database):
  263.                 b_type, b_mode, b_factor, b_sub = database[n-1]
  264.                 if b_mode == 's':
  265.                     database[n-1] = b_type, 'i', a_factor, `i`
  266.                     n_in_args = n_in_args - 1
  267.     #
  268.     # Assign argument positions in the Python argument list
  269.     #
  270.     in_pos = []
  271.     i_in = 0
  272.     for i in range(len(database)):
  273.         a_type, a_mode, a_factor, a_sub = database[i]
  274.         if a_mode == 's':
  275.             in_pos.append(i_in)
  276.             i_in = i_in + 1
  277.         else:
  278.             in_pos.append(-1)
  279.     #
  280.     # Get input arguments
  281.     #
  282.     for i in range(len(database)):
  283.         a_type, a_mode, a_factor, a_sub = database[i]
  284.         if a_type[:9] == 'unsigned ':
  285.             xtype = a_type[9:]
  286.         else:
  287.             xtype = a_type
  288.         if a_mode == 'i':
  289.             #
  290.             # Implicit argument;
  291.             # a_factor is divisor if present,
  292.             # a_sub indicates which arg (`database index`)
  293.             #
  294.             j = eval(a_sub)
  295.             print '\tif',
  296.             print '(!geti' + xtype + 'arraysize(args,',
  297.             print `n_in_args` + ',',
  298.             print `in_pos[j]` + ',',
  299.             if xtype <> a_type:
  300.                 print '('+xtype+' *)',
  301.             print '&arg' + `i+1` + '))'
  302.             print '\t\treturn NULL;'
  303.             if a_factor:
  304.                 print '\targ' + `i+1`,
  305.                 print '= arg' + `i+1`,
  306.                 print '/', a_factor + ';'
  307.         elif a_mode == 's':
  308.             if a_sub and not isnum(a_sub):
  309.                 # Allocate memory for varsize array
  310.                 print '\tif ((arg' + `i+1`, '=',
  311.                 if a_factor:
  312.                     print '('+a_type+'(*)['+a_factor+'])',
  313.                 print 'NEW(' + a_type, ',',
  314.                 if a_factor:
  315.                     print a_factor, '*',
  316.                 print a_sub, ')) == NULL)'
  317.                 print '\t\treturn err_nomem();'
  318.             print '\tif',
  319.             if a_factor or a_sub: # Get a fixed-size array array
  320.                 print '(!geti' + xtype + 'array(args,',
  321.                 print `n_in_args` + ',',
  322.                 print `in_pos[i]` + ',',
  323.                 if a_factor: print a_factor,
  324.                 if a_factor and a_sub: print '*',
  325.                 if a_sub: print a_sub,
  326.                 print ',',
  327.                 if (a_sub and a_factor) or xtype <> a_type:
  328.                     print '('+xtype+' *)',
  329.                 print 'arg' + `i+1` + '))'
  330.             else: # Get a simple variable
  331.                 print '(!geti' + xtype + 'arg(args,',
  332.                 print `n_in_args` + ',',
  333.                 print `in_pos[i]` + ',',
  334.                 if xtype <> a_type:
  335.                     print '('+xtype+' *)',
  336.                 print '&arg' + `i+1` + '))'
  337.             print '\t\treturn NULL;'
  338.     #
  339.     # Begin of function call
  340.     #
  341.     if type <> 'void':
  342.         print '\tretval =', func + '(',
  343.     else:
  344.         print '\t' + func + '(',
  345.     #
  346.     # Argument list
  347.     #
  348.     for i in range(len(database)):
  349.         if i > 0: print ',',
  350.         a_type, a_mode, a_factor, a_sub = database[i]
  351.         if a_mode == 'r' and not a_factor:
  352.             print '&',
  353.         print 'arg' + `i+1`,
  354.     #
  355.     # End of function call
  356.     #
  357.     print ');'
  358.     #
  359.     # Free varsize arrays
  360.     #
  361.     for i in range(len(database)):
  362.         a_type, a_mode, a_factor, a_sub = database[i]
  363.         if a_mode == 's' and a_sub and not isnum(a_sub):
  364.             print '\tDEL(arg' + `i+1` + ');'
  365.     #
  366.     # Return
  367.     #
  368.     if n_out_args:
  369.         #
  370.         # Multiple return values -- construct a tuple
  371.         #
  372.         if type <> 'void':
  373.             n_out_args = n_out_args + 1
  374.         if n_out_args == 1:
  375.             for i in range(len(database)):
  376.                 a_type, a_mode, a_factor, a_sub = database[i]
  377.                 if a_mode == 'r':
  378.                     break
  379.             else:
  380.                 raise arg_error, 'expected r arg not found'
  381.             print '\treturn',
  382.             print mkobject(a_type, 'arg' + `i+1`) + ';'
  383.         else:
  384.             print '\t{ object *v = newtupleobject(',
  385.             print n_out_args, ');'
  386.             print '\t  if (v == NULL) return NULL;'
  387.             i_out = 0
  388.             if type <> 'void':
  389.                 print '\t  settupleitem(v,',
  390.                 print `i_out` + ',',
  391.                 print mkobject(type, 'retval') + ');'
  392.                 i_out = i_out + 1
  393.             for i in range(len(database)):
  394.                 a_type, a_mode, a_factor, a_sub = database[i]
  395.                 if a_mode == 'r':
  396.                     print '\t  settupleitem(v,',
  397.                     print `i_out` + ',',
  398.                     s = mkobject(a_type, 'arg' + `i+1`)
  399.                     print s + ');'
  400.                     i_out = i_out + 1
  401.             print '\t  return v;'
  402.             print '\t}'
  403.     else:
  404.         #
  405.         # Simple function return
  406.         # Return None or return value
  407.         #
  408.         if type == 'void':
  409.             print '\tINCREF(None);'
  410.             print '\treturn None;'
  411.         else:
  412.             print '\treturn', mkobject(type, 'retval') + ';'
  413.     #
  414.     # Stub body closing brace
  415.     #
  416.     print '}'
  417.  
  418.  
  419. # Subroutine to return a function call to mknew<type>object(<arg>)
  420. #
  421. def mkobject(type, arg):
  422.     if type[:9] == 'unsigned ':
  423.         type = type[9:]
  424.         return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
  425.     return 'mknew' + type + 'object(' + arg + ')'
  426.  
  427.  
  428. defined_archs = []
  429.  
  430. # usage: cgen [ -Dmach ... ] [ file ]
  431. for arg in sys.argv[1:]:
  432.     if arg[:2] == '-D':
  433.         defined_archs.append(arg[2:])
  434.     else:
  435.         # Open optional file argument
  436.         sys.stdin = open(arg, 'r')
  437.  
  438.  
  439. # Input line number
  440. lno = 0
  441.  
  442.  
  443. # Input is divided in two parts, separated by a line containing '%%'.
  444. #    <part1>        -- literally copied to stdout
  445. #    <part2>        -- stub definitions
  446.  
  447. # Variable indicating the current input part.
  448. #
  449. part = 1
  450.  
  451. # Main loop over the input
  452. #
  453. while 1:
  454.     try:
  455.         line = raw_input()
  456.     except EOFError:
  457.         break
  458.     #
  459.     lno = lno+1
  460.     words = string.split(line)
  461.     #
  462.     if part == 1:
  463.         #
  464.         # In part 1, copy everything literally
  465.         # except look for a line of just '%%'
  466.         #
  467.         if words == ['%%']:
  468.             part = part + 1
  469.         else:
  470.             #
  471.             # Look for names of manually written
  472.             # stubs: a single percent followed by the name
  473.             # of the function in Python.
  474.             # The stub name is derived by prefixing 'gl_'.
  475.             #
  476.             if words and words[0][0] == '%':
  477.                 func = words[0][1:]
  478.                 if (not func) and words[1:]:
  479.                     func = words[1]
  480.                 if func:
  481.                     functions.append(func)
  482.             else:
  483.                 print line
  484.         continue
  485.     if not words:
  486.         continue        # skip empty line
  487.     elif words[0] == 'if':
  488.         # if XXX rest
  489.         # if !XXX rest
  490.         if words[1][0] == '!':
  491.             if words[1][1:] in defined_archs:
  492.                 continue
  493.         elif words[1] not in defined_archs:
  494.             continue
  495.         words = words[2:]
  496.     if words[0] == '#include':
  497.         print line
  498.     elif words[0][:1] == '#':
  499.         pass            # ignore comment
  500.     elif words[0] not in return_types:
  501.         err('Line', lno, ': bad return type :', words[0])
  502.     elif len(words) < 2:
  503.         err('Line', lno, ': no funcname :', line)
  504.     else:
  505.         if len(words) % 2 <> 0:
  506.             err('Line', lno, ': odd argument list :', words[2:])
  507.         else:
  508.             database = []
  509.             try:
  510.                 for i in range(2, len(words), 2):
  511.                     x = checkarg(words[i], words[i+1])
  512.                     database.append(x)
  513.                 print
  514.                 print '/*',
  515.                 for w in words: print w,
  516.                 print '*/'
  517.                 generate(words[0], words[1], database)
  518.             except arg_error, msg:
  519.                 err('Line', lno, ':', msg)
  520.  
  521.  
  522. print
  523. print 'static struct methodlist gl_methods[] = {'
  524. for func in functions:
  525.     print '\t{"' + func + '", gl_' + func + '},'
  526. print '\t{NULL, NULL} /* Sentinel */'
  527. print '};'
  528. print
  529. print 'initgl()'
  530. print '{'
  531. print '\tinitmodule("gl", gl_methods);'
  532. print '}'
  533.